package com.example.backend.service.impl;

import com.example.backend.common.api.ResultCode;
import com.example.backend.common.exception.BusinessException;
import com.example.backend.common.utils.IpUtils;
import com.example.backend.common.utils.JwtUtils;
import com.example.backend.dto.RegisterDTO;
import com.example.backend.entity.*;
import com.example.backend.mapper.UserRoleMapper;
import com.example.backend.service.AuthService;
import com.example.backend.service.TokenService;
import com.example.backend.service.TokenBlacklistService;
import com.example.backend.service.UserService;
import com.example.backend.service.OperationLogService;
import com.example.backend.service.OnlineUserService;
import com.example.backend.service.CaptchaService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import jakarta.servlet.http.HttpServletRequest;

/**
 * 认证服务实现类
 */
@Service
@RequiredArgsConstructor
public class AuthServiceImpl implements AuthService {
    
    private final UserService userService;
    private final UserRoleMapper userRoleMapper;
    private final PasswordEncoder passwordEncoder;
    private final JwtUtils jwtUtils;
    private final TokenService tokenService;
    private final TokenBlacklistService blacklistService;
    private final OperationLogService operationLogService;
    private final OnlineUserService onlineUserService;
    private final HttpServletRequest request;
    private final CaptchaService captchaService;

    @Override
    public String login(String username, String password) {
        try {
            // 1. 查询用户
            User user = userService.getByUsername(username);
            if (user == null) {
                throw new BusinessException(ResultCode.USER_NOT_FOUND);
            }
            
            // 2. 校验密码
            if (!passwordEncoder.matches(password, user.getPassword())) {
                throw new BusinessException(ResultCode.PASSWORD_ERROR);
            }
            
            // 3. 校验用户状态
            if (user.getStatus() != 1) {
                throw new BusinessException("账号已被禁用");
            }
            
            // 4. 判断用户角色
            boolean isAdmin = user.getRoles().stream()
                    .map(Role::getCode)
                    .anyMatch(code -> code.equals("ROLE_ADMIN"));
            
            // 获取用户权限
            List<String> authorities = user.getRoles().stream()
                    .flatMap(role -> {
                        List<String> perms = new ArrayList<>();
                        // 添加角色
                        perms.add(role.getCode());
                        // 添加权限
                        perms.addAll(role.getPermissions().stream()
                                .map(Permission::getCode)
                                .collect(Collectors.toList()));
                        return perms.stream();
                    })
                    .collect(Collectors.toList());
            
            // 5. 生成Token
            Map<String, Object> claims = new HashMap<>();
            claims.put("userId", user.getId());
            claims.put("username", user.getUsername());
            claims.put("isAdmin", isAdmin);
            claims.put("authorities", authorities);
            
            String token = jwtUtils.generateToken(username, claims);
            
            // 存储Token
            tokenService.storeToken(user.getId(), token);
            
            // 记录登录日志
            OperationLog log = new OperationLog();
            log.setModule("认证");
            log.setType("登录");
            log.setDescription("用户登录");
            log.setUserId(user.getId());
            log.setUsername(username);
            log.setIp(IpUtils.getIpAddr());
            log.setMethod("POST");
            log.setUrl("/auth/login");
            log.setStatus(1);
            operationLogService.save(log);
            
            // 记录在线用户
            onlineUserService.recordOnlineUser(token, user.getId(), username, request);
            
            return token;
        } catch (Exception e) {
            // 记录登录失败日志
            OperationLog log = new OperationLog();
            log.setModule("认证");
            log.setType("登录");
            log.setDescription("用户登录");
            log.setUsername(username);
            log.setIp(IpUtils.getIpAddr());
            log.setMethod("POST");
            log.setUrl("/auth/login");
            log.setStatus(0);
            log.setErrorMsg(e.getMessage());
            operationLogService.save(log);
            
            throw e;
        }
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean register(RegisterDTO registerDTO) {
        // 验证验证码
        if (!captchaService.verifyCaptcha(registerDTO.getEmail(), 
                registerDTO.getCaptcha(), "register")) {
            throw new BusinessException(ResultCode.INVALID_CAPTCHA);
        }
        
        // 1. 检查用户名是否存在
        if (userService.checkUsernameExists(registerDTO.getUsername())) {
            throw new BusinessException(ResultCode.USERNAME_EXISTS);
        }
        
        // 2. 检查邮箱是否存在
        if (userService.checkEmailExists(registerDTO.getEmail())) {
            throw new BusinessException(ResultCode.EMAIL_EXISTS);
        }
        
        // 3. 创建用户
        User user = new User();
        user.setUsername(registerDTO.getUsername());
        user.setPassword(passwordEncoder.encode(registerDTO.getPassword()));
        user.setNickname(registerDTO.getNickname());
        user.setEmail(registerDTO.getEmail());
        user.setPhone(registerDTO.getPhone());
        user.setStatus(1);
        
        if (!userService.save(user)) {
            throw new BusinessException(ResultCode.REGISTER_FAIL);
        }
        
        // 4. 分配默认角色（普通用户）
        UserRole userRole = new UserRole();
        userRole.setUserId(user.getId());
        userRole.setRoleId(2L); // 普通用户角色ID
        
        if (userRoleMapper.insert(userRole) <= 0) {
            throw new BusinessException(ResultCode.REGISTER_FAIL);
        }
        
        return true;
    }
    
    @Override
    public String refreshToken() {
        // 1. 获取当前用户认证信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) {
            throw new BusinessException(ResultCode.UNAUTHORIZED);
        }
        
        // 2. 获取用户信息
        String username = authentication.getName();
        User user = userService.getByUsername(username);
        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_FOUND);
        }
        
        // 3. 生成新Token
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", user.getId());
        claims.put("username", user.getUsername());
        claims.put("isAdmin", user.getRoles().stream()
                .map(Role::getCode)
                .anyMatch(code -> code.equals("ROLE_ADMIN")));
        claims.put("authorities", user.getRoles().stream()
                .map(Role::getCode)
                .toList());
        
        return jwtUtils.generateToken(username, claims);
    }
    
    @Override
    public void logout() {
        try {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (authentication != null && authentication.isAuthenticated()) {
                String token = jwtUtils.getTokenFromRequest();
                if (token != null) {
                    Long userId = jwtUtils.getUserIdFromToken(token);
                    tokenService.removeToken(userId);
                    blacklistService.addToBlacklist(token, jwtUtils.getExpiration());
                    
                    // 记录登出日志
                    OperationLog log = new OperationLog();
                    log.setModule("认证");
                    log.setType("登出");
                    log.setDescription("用户登出");
                    log.setUserId(userId);
                    log.setUsername(authentication.getName());
                    log.setIp(IpUtils.getIpAddr());
                    log.setMethod("POST");
                    log.setUrl("/auth/logout");
                    log.setStatus(1);
                    operationLogService.save(log);
                    
                    // 清除在线用户记录
                    onlineUserService.logout(token);
                }
            }
        } finally {
            SecurityContextHolder.clearContext();
        }
    }
} 